﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;

namespace Saxxon.Graphics
{
    /// <summary>
    /// A 32-bit bitmap where each pixel is individually addressible.
    /// </summary>
    sealed public class RawBitmap : IDisposable
    {
        /// <summary>
        /// Create a RawBitmap with the specified size in pixels.
        /// </summary>
        public RawBitmap(Size size)
        {
            this.Size = size;
            Initialize();
        }

        /// <summary>
        /// Create a RawBitmap with the specified dimensions in pixels.
        /// </summary>
        public RawBitmap(int width, int height)
        {
            this.Size = new Size(width, height);
            Initialize();
        }

        /// <summary>
        /// Destructor for RawBitmap.
        /// </summary>
        ~RawBitmap()
        {
            Dispose();
        }

        /// <summary>
        /// Managed Bitmap object.
        /// </summary>
        public Bitmap Bitmap { get; private set; }

        /// <summary>
        /// Set all pixels to the clear color.
        /// </summary>
        public void Clear(Color clearColor)
        {
            int count = Pixels.Length;
            Int32 value = clearColor.ToArgb();

            for (int i = 0; i < count; i++)
                Pixels[i] = value;
        }

        /// <summary>
        /// Dispose the object and free all unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            if (!IsDisposed)
            {
                Bitmap.Dispose();
                Pointer = IntPtr.Zero;
                if (Handle.IsAllocated)
                    Handle.Free();
            }
        }

        /// <summary>
        /// Garbage collection handle.
        /// </summary>
        private GCHandle Handle { get; set; }

        /// <summary>
        /// Height of the bitmap in pixels.
        /// </summary>
        public int Height { get { return Size.Height; } }

        /// <summary>
        /// Initialize the RawBitmap. Dimensions must have been initialized prior to calling this method.
        /// </summary>
        private void Initialize()
        {
            // create pixel buffer
            Pixels = new Int32[Size.Width * Size.Height];

            // pin the pixel buffer in memory
            Handle = GCHandle.Alloc(Pixels);
            Pointer = Handle.AddrOfPinnedObject();

            // create bitmap object
            Bitmap = new Bitmap(Size.Width, Size.Height, Size.Width * 4, PixelFormat.Format32bppPArgb, Pointer);

            // perform initial clear
            Clear(Color.Black);
        }

        /// <summary>
        /// If false, the object has not yet been disposed.
        /// </summary>
        public bool IsDisposed { get; private set; }

        /// <summary>
        /// Raw pixel data.
        /// </summary>
        public Int32[] Pixels { get; private set; }

        /// <summary>
        /// Pointer to raw pixel memory.
        /// </summary>
        public IntPtr Pointer { get; private set; }

        /// <summary>
        /// Size of the bitmap in pixels.
        /// </summary>
        public Size Size { get; private set; }

        /// <summary>
        /// Width of the bitmap in pixels.
        /// </summary>
        public int Width { get { return Size.Width; } }
    }
}
